/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pos.system;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import java.io.PrintStream;
import java.util.Calendar;
import java.util.Enumeration;
import java.util.Locale;

/**
 *
 * @author Shameera
 */
public class PosPrinter {

    private Order order;
    CommPortIdentifier portId;
    Enumeration portList;
    private SerialPort port;
    private PrintStream out;
    private CommPort serialPort;
    private String defaultPort = "COM1";
    private final boolean isPrinterPresent;

    public PosPrinter(Order order, boolean isPrinterPresent) {
        this.order = order;
        this.isPrinterPresent = isPrinterPresent;
//        init();
    }

    public void printBill() {
        init();
        printHeader();
        printOrder();
        printFooter();
        close();
    }

    private void printHeader() {
        if (out == null && isPrinterPresent) {
            init();
        }
        if (isPrinterPresent) {
            if (out == null) {
                init();
            }
            out.println(buildCenterString(Constants.COMPANY_NAME));
            out.println(buildCenterString(Constants.COMPANY_ADDRESS));
            out.println(buildCenterString(Constants.COMPANY_TP));
            out.println();
            out.println(getDate());
            out.println(buildCenterString(Constants.INVOICE_NUM + order.getInvoiceNum()));
            out.println(getItemHeader());
        } else {
            buildCenterString(Constants.COMPANY_NAME);
            buildCenterString(Constants.COMPANY_ADDRESS);
            buildCenterString(Constants.COMPANY_TP);
            System.out.println("");
            getDate();
            buildCenterString(Constants.INVOICE_NUM + order.getInvoiceNum());
            getItemHeader();
        }
    }

    private String getDate() {

        Calendar calendar = Calendar.getInstance(Locale.ENGLISH);
        int y = calendar.get(Calendar.YEAR);
        String m_s = calendar.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.ENGLISH);
        int d = calendar.get(Calendar.DAY_OF_MONTH);
        int h = calendar.get(Calendar.HOUR);
        int min = calendar.get(Calendar.MINUTE);
        int sec = calendar.get(Calendar.SECOND);
        String apm = calendar.getDisplayName(Calendar.AM_PM, Calendar.LONG, Locale.ENGLISH);
        String date = (m_s + " " + d + ", " + y + "  " + h + ":" + min + ":" + sec + " " + apm);
        test(date);
        return date;
    }

    private void printFooter() {
        if (isPrinterPresent) {
            if (out == null) {
                init();
            }

            out.println(buildCenterString(Constants.THANK_YOU));
            out.println(buildCenterString(Constants.PRINTER_SEPERATOR));
            out.println(buildCenterString(Constants.LEAFPOS_TAG));
            out.println(buildCenterString(Constants.LEAFPOS_CONTACT_1 + "   " + Constants.LEAFPOS_CONTACT_2));

            out.println("\n\n\n");
        } else {

            buildCenterString(Constants.THANK_YOU);
            buildCenterString(Constants.PRINTER_SEPERATOR);
            buildCenterString(Constants.LEAFPOS_TAG);
            buildCenterString(Constants.LEAFPOS_CONTACT_1 + "   " + Constants.LEAFPOS_CONTACT_2);

            test("\n\n\n");
        }

    }

    private String buildCenterString(String str) {
        int l_diff = Constants.PRINTER_WIDTH - str.length();
        StringBuilder sb = new StringBuilder(str);
        if (l_diff > 1) {
            int gap = l_diff / 2;
            for (int k = 0; k < gap; k++) {
                sb.insert(0, " ");
                sb.append(" ");
            }
        }
        String item_ = sb.toString();
        test(item_);
        return item_;
    }

    private String printItemString(String code, String name, int qty, String unitPrice, String totalPrice) {
        StringBuilder sb = new StringBuilder();
        int temp_length = code.length();
        if (temp_length == Constants.BILL_CODE_LENGTH) {
            sb.append(code);
        } else if (temp_length < Constants.BILL_CODE_LENGTH) {
            sb.append(code);
            int k = Constants.BILL_CODE_LENGTH - temp_length;
            for (int j = 0; j < k; j++) {
                sb.append(" ");
            }
        } else {
            sb.append(code.substring(0, Constants.BILL_CODE_LENGTH));
        }

        sb.append("  ");

        temp_length = name.length();
        if (temp_length == Constants.BILL_NAME_LENGTH) {
            sb.append(name);
        } else if (temp_length < Constants.BILL_NAME_LENGTH) {
            sb.append(name);
            int k = Constants.BILL_NAME_LENGTH - temp_length;
            for (int j = 0; j < k; j++) {
                sb.append(" ");
            }
        } else {
            sb.append(name.substring(0, Constants.BILL_NAME_LENGTH - 1));
        }
        sb.append("\n");
        int i = Constants.PRINTER_WIDTH - (Constants.BILL_ITEM_TOTAL_LENGTH + 3 + Constants.BILL_UNIT_PRICE_LENGTH + 1 + Constants.BILL_QTY_LENGTH);
        for (int j = 0; j < i; j++) {
            sb.append(" ");
        }
        temp_length = ("" + qty).length();
        if (temp_length == Constants.BILL_QTY_LENGTH) {
            sb.append(("" + qty));
        } else if (temp_length < Constants.BILL_QTY_LENGTH) {

            int k = Constants.BILL_QTY_LENGTH - temp_length;
            for (int j = 0; j < k; j++) {
                sb.append(" ");
            }
            sb.append(("" + qty));
        } else {
            sb.append(("" + qty).substring(0, Constants.BILL_QTY_LENGTH - 1));
        }
        sb.append("X");

        temp_length = unitPrice.length();
        if (temp_length == Constants.BILL_UNIT_PRICE_LENGTH) {
            sb.append(unitPrice);
        } else if (temp_length < Constants.BILL_UNIT_PRICE_LENGTH) {

            int k = Constants.BILL_UNIT_PRICE_LENGTH - temp_length;
            for (int j = 0; j < k; j++) {
                sb.append(" ");
            }
            sb.append(unitPrice);
        } else {
            sb.append(unitPrice.substring(0, Constants.BILL_UNIT_PRICE_LENGTH - 1));
        }

        sb.append("   ");

        temp_length = totalPrice.length();
        if (temp_length == Constants.BILL_TOTAL_PIRCE_LENGTH) {
            sb.append(totalPrice);
        } else if (temp_length < Constants.BILL_TOTAL_PIRCE_LENGTH) {

            int k = Constants.BILL_TOTAL_PIRCE_LENGTH - temp_length;
            for (int j = 0; j < k; j++) {
                sb.append(" ");
            }
            sb.append(totalPrice);
        } else {
            sb.append(totalPrice.substring(0, Constants.BILL_TOTAL_PIRCE_LENGTH - 1));
        }
        String item_ = sb.toString();
        test(item_);
        return item_;
    }

    private String printTCBString(String str, String money) {
        StringBuilder sb = new StringBuilder(str);
        int gap = Constants.PRINTER_WIDTH - (str.length() + money.length());
        for (int i = 0; i < gap; i++) {
            sb.append(" ");
        }
        sb.append(money);

        String item_ = sb.toString();
        test(item_);
        return item_;
    }

    private void printOrder() {
        if (isPrinterPresent) {
            if (out == null) {
                init();
            }
            for (OrderItem item : order.getItems()) {
                out.println(printItemString(item.getCode(), item.getName(), item.getAmount(), item.getPriceAsMoneyString(), item.getTotalPriceAsMoneyString()));
            }
            out.println(buildCenterString(Constants.PRINTER_SEPERATOR));

            out.println(printTCBString("TOTAL", order.getTotalAsMoneyString()));
            out.println(printTCBString("CASH", order.getCashAsMoneyString()));
            out.println(printTCBString("BALANCE", order.getBalanceAsMoneyString()));
        } else {
            for (OrderItem item : order.getItems()) {
                printItemString(item.getCode(), item.getName(), item.getAmount(), item.getPriceAsMoneyString(), item.getTotalPriceAsMoneyString());
            }
            buildCenterString(Constants.PRINTER_SEPERATOR);

            printTCBString("TOTAL", order.getTotalAsMoneyString());
            printTCBString("CASH", order.getCashAsMoneyString());
            printTCBString("BALANCE", order.getBalanceAsMoneyString());
        }

    }

    private void init() {
        if (isPrinterPresent) {
            try {
                boolean portFound = false;
                portList = CommPortIdentifier.getPortIdentifiers();

                while (portList.hasMoreElements() && !portFound) {
                    portId = (CommPortIdentifier) portList.nextElement();
                    if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                        if (portId.getName().equals(defaultPort)) {
                            System.out.println("Found port: " + defaultPort);
                            portFound = true;
                            serialPort = portId.open("SerialPort", 200);
                            port = (SerialPort) serialPort;
                            port.setSerialPortParams(19200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                            out = new PrintStream(port.getOutputStream(), true, "US-ASCII");
                        }
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

    }

    private void close() {
        if (out != null) {
            out.flush();
            out.close();
        }

        if (serialPort != null) {
            serialPort.close();
        }
    }

    private String getItemHeader() {
        String headers = Constants.BILL_CODE_HEADER + " " + Constants.BILL_NAME_HEADER + " " + Constants.BILL_QTY_HEADER + " "
                + Constants.BILL_UNIT_PRICE_HEADER + "   " + Constants.BILL_TOTAL_HEADER;
        test(headers);
        return headers;
    }

    private void test(String toString) {
        if (!isPrinterPresent) {
            System.out.println(toString);
        }
    }
}
